-- Brethren RaidFrames oUF layout by Xenios
-- use /brf to move frames

local ADDON_NAME, ns = ...
local oUF = ns.oUF or oUF
assert(oUF, "oUF is not installed??")

-- ***************
-- * Helper Functions / Variables 
-- ***************

-- The backdrop Texture
local backdrop = {
	bgFile = [=[Interface\ChatFrame\ChatFrameBackground]=],
	insets = {top = 0, left = 0, bottom = 0, right = 0},
}

-- The border Texture
local border = {}


-- Converts decimal color values to text color format
local function hex(r, g, b)
	if(type(r) == 'table') then
		if(r.r) then r, g, b = r.r, r.g, r.b else r, g, b = unpack(r) end
	end
	return ('|cff%02x%02x%02x'):format(r * 255, g * 255, b * 255)
end

local thinBorder = {
		bgFile = [=[Interface\AddOns\oUF_BrethrenRF\media\white.tga]=],
		insets = {top = -1, left = -1, bottom = -1, right = -1},
}


-- Returns a color array that is adjusted to the given percentage
local ColorGradient = function(perc, color1, color2, color3)
	local r1,g1,b1 = color1[1],color1[2],color1[3]
	local r2,g2,b2 = color2[1],color2[2],color2[3]
	local r3,g3,b3 = color3[1],color3[2],color3[3]
	
	-- the two extremes
	if perc >= 1 then
		return r3, g3, b3
	elseif perc <= 0 then
		return r1, g1, b1
	end

	local segment, relperc = math.modf(perc*(3-1))
	local offset = (segment*3)+1

	-- < 50% > 0%
	if(offset == 1) then
		return r1 + (r2-r1)*relperc, g1 + (g2-g1)*relperc, b1 + (b2-b1)*relperc
	end
	-- < 99% > 50%
	return r2 + (r3-r2)*relperc, g2 + (g3-g2)*relperc, b2 + (b3-b2)*relperc
end


-- Shortens the given value to save space. example: 10000 becomes 10k 
local shorten = function(value)
	if value >= 1e7 then
		return ('%.1fm'):format(value / 1e6):gsub('%.?0+([km])$', '%1')
	elseif value >= 1e6 then
		return ('%.2fm'):format(value / 1e6):gsub('%.?0+([km])$', '%1')
	elseif value >= 1e5 then
		return ('%.0fk'):format(value / 1e3)
	elseif value >= 1e3 then
		return ('%.1fk'):format(value / 1e3):gsub('%.?0+([km])$', '%1')
	else
		return value
	end
end

-- Shortens name
local function utf8sub(str, start, numChars) 
	local currentIndex = start 
	while numChars > 0 and currentIndex <= #str do 
		local char = string.byte(str, currentIndex) 
		if char >= 240 then 
			currentIndex = currentIndex + 4 
		elseif char >= 225 then 
			currentIndex = currentIndex + 3 
		elseif char >= 192 then 
			currentIndex = currentIndex + 2 
		else 
			currentIndex = currentIndex + 1 
		end 
		numChars = numChars - 1 
	end 
	return str:sub(start, currentIndex - 1) 
end 

-- Returns the group number of the given unit, if you are in a party or solo 1 is returned.
local getGroupNumber = function (unit)
	if UnitInRaid("player") then
		local myname = UnitName('player')
		for i = 1 , GetNumRaidMembers() do
			local name = GetRaidRosterInfo(i)
			if ( name == myname ) then
				return subgroup
			end
		end
	elseif UnitInParty("player") then
		return 1
	else
		return 1
	end
end

-- Unit Menu
local dropdown = CreateFrame("Frame", "MyAddOnUnitDropDownMenu", UIParent, "UIDropDownMenuTemplate")

UIDropDownMenu_Initialize(dropdown, function(self)
	local unit = self:GetParent().unit
	if not unit then return end

	local menu, name, id
	if UnitIsUnit(unit, "player") then
		menu = "SELF"
	elseif UnitIsUnit(unit, "vehicle") then
		menu = "VEHICLE"
	elseif UnitIsUnit(unit, "pet") then
		menu = "PET"
	elseif UnitIsPlayer(unit) then
		id = UnitInRaid(unit)
		if id then
			menu = "RAID_PLAYER"
			name = GetRaidRosterInfo(id)
		elseif UnitInParty(unit) then
			menu = "PARTY"
		else
			menu = "PLAYER"
		end
	else
		menu = "TARGET"
		name = RAID_TARGET_ICON
	end
	if menu then
		UnitPopup_ShowMenu(self, menu, unit, name, id)
	end
end, "MENU")

local menu = function(self)
	dropdown:SetParent(self)
	ToggleDropDownMenu(1, nil, dropdown, "cursor", 0, 0)
end


-- used to make sure the textures do not tile
local fixStatusbar = function(bar)
	bar:GetStatusBarTexture():SetHorizTile(false)
	bar:GetStatusBarTexture():SetVertTile(false)
end

-- Used to find out when to display dispellable debuffs
local _, class = UnitClass("player")
local dispellClass = {
	PRIEST = { Magic = true, Disease = true, },
	SHAMAN = { Curse = true, Magic = true, },
	PALADIN = { Magic = true, Poison = true, Disease = true, },
	MAGE = { Curse = true, },
	DRUID = { Curse = true, Poison = true, Magic = true, },
}
local dispellist = dispellClass[class] or {}
local dispellPriority = {
	Magic = 4,
	Poison = 3,
	Curse = 2,
	Disease = 1,
}

local updateOccurenceStore = function(unit)
	if UnitPlayerOrPetInRaid(unit) or UnitPlayerOrPetInParty(unit) or unit == "player" then
		if not ns.occurrences[unit] then 
			--print("Creating occurrences for ".. unit)
			-- create new table if one does not exist
			ns.occurrences[unit] = {}
			local unitOccurences = ns.occurrences[unit]
			-- create values for each occurence buff
			for key,value in pairs(ns.auras.bottomBar) do 
				if value[6] and not value[7] then 
					unitOccurences[key] = 0
				end 
			end
		end
	else
		--print(unit.." is not you or in your party/raid")
		-- remove unit from table
		if ns.occurrences[unit] then ns.occurrences[unit]=nil end
	end
end

local updateOccurenceStoreEvent = function(self)
	updateOccurenceStore(self.unit)
end



-- Hide the blizzard frames
CompactRaidFrameManager:UnregisterAllEvents()
CompactRaidFrameManager:Hide()
CompactRaidFrameContainer:UnregisterAllEvents()
CompactRaidFrameContainer:Hide() 

-- ***************
-- * oUF Tags
-- ***************

-- Displays the name of the unit. If the unit has aggro, their name turns red.
local nameCache = {}
oUF.Tags['BRFname'] = function(u, r)
	local name = UnitName(r or u) or "unknown"
	local _, class = UnitClass(u)
	local color
	local shortName
	if class and not ns.db.useClassColor then
		color = hex(oUF.colors.class[class])
	else
		color = hex(ns.db.defaultTextColor)
	end
	if(UnitThreatSituation(r or u) == 3) then 
		color = hex(ns.db.aggroColor)
	end
	if nameCache[name] then
		shortName = nameCache[name]
	else 
		shortName = utf8sub(name, 1, ns.db.nameLength)
		nameCache[name] = shortName
	end
	
	local str = color..shortName.."|r"
	return str
end
oUF.TagEvents['BRFname'] = 'UNIT_NAME_UPDATE PLAYER_ENTERING_WORLD UNIT_THREAT_LIST_UPDATE UNIT_THREAT_SITUATION_UPDATE PARTY_MEMBERS_CHANGED RAID_ROSTER_UPDATE'


-- Displays group number, hot count, or buff stacks depending on settings and what buffs are present on the unit
oUF.Tags['BRFGroupHotCount'] = function (u)
	local cur = 0
	local curName = nil
	local text = "  "
	local index=1
	--local occurances = {}
	if ns.db.displayBuffCounter then
		-- Loop until there are no more buffs
		while true do
			local name, _, _, count, _, _, _, unitCaster = UnitAura(u, index, "HELPFUL")
			if not name then break end
			-- Check to see if current buff has been specified by the user and if they want it tracked here
			if ns.auras.bottomBar[name] and ns.auras.bottomBar[name][6] and ((not ns.db.displayNonClassBuffs and ns.auras.bottomBar[name][9] == class) or ns.db.displayNonClassBuffs) then
				local currBuffSettings = ns.auras.bottomBar[name]
				-- if the current buff has the highest priority so far, lets use it
				if currBuffSettings[5] > cur then
					cur = currBuffSettings[5]
					-- If the current buff should use occurances, lets start counting. But make sure that we keep track of its name for later
					if not currBuffSettings[7] then
						curName = name
						if not ns.occurrences[u] then 
							updateOccurenceStore(u) 
						end
						-- Fix bug of someone entering a vechile while having hots or something.
						if ns.occurrences[u][name] then 
							ns.occurrences[u][name] = ns.occurrences[u][name] + 1
						end
					-- The current buff is monitored by stacks so we can set the text var with the count directly.	
					else
						curName = name
						
						text = hex(currBuffSettings[1],currBuffSettings[2],currBuffSettings[3],currBuffSettings[4]) .. count
					end
				end
			end
			index = index + 1
		end
		-- check to see if the highest priority buff was monitored by occurances. If so then set the text var.
		if curName and not ns.auras.bottomBar[curName][7] then
			text = hex(unpack(ns.auras.bottomBar[curName])) .. ns.occurrences[u][curName]
		end
		-- reset all counts for current unit to 0
		if ns.occurrences[u] then
			for key,value in pairs(ns.occurrences[u]) do 
				ns.occurrences[u][key]=0
			end
		end
	end
	
	-- if the user wishes to display group number and there are no buffs being monitored, show the group number
	if  ns.db.displayGroupNumber and (not ns.db.displayBuffCounter or cur == 0) then
		text = hex(ns.db.defaultTextColor) .. getGroupNumber(u)
	end
	--occurances = nil
	return text
end
oUF.TagEvents['BRFGroupHotCount'] = 'UNIT_AURA PARTY_MEMBER_CHANGED'


-- Displays the amount of health missing from the unit. If an incomming heal is present, display that as well.
oUF.Tags['BRFhealth'] = function(unit)
	local text=""
	local uh,uhm = UnitHealth(unit),UnitHealthMax(unit);
	local mis = uhm-uh
	local status = not UnitIsConnected(unit) and 'Offline' or UnitIsGhost(unit) and 'Ghost' or UnitIsDead(unit) and 'Dead'
	local ih = 0
	
	-- Thank you blizzard for not making everyone use a shitty lib for this
	if ns.db.healPrediction and ns.db.healPredictionText then
		ih = UnitGetIncomingHeals(unit)
	end

	if(status) then
		return status
	end
	
	text =  hex(ColorGradient(uh/uhm,ns.db.healthTextColorEnd,ns.db.healthTextColorMid,ns.db.healthTextColor)) .. "-" .. shorten(mis);
	-- if Incomming heal is detected, lets display it.
	if ((mis > 0) and ((ih or 0) > 0)) then
		text = text .. "(" .. hex(ns.db.predictedHealthTextColor) .. "+" .. shorten(ih) .. hex(ColorGradient(uh/uhm,ns.db.healthTextColorEnd,ns.db.healthTextColorMid,ns.db.healthTextColor)) .. ")";
	end
	return text
end
oUF.TagEvents['BRFhealth'] = 'UNIT_HEAL_PREDICTION UNIT_HEALTH UNIT_MAXHEALTH'

local pomCount = {"i","h","g","f","Z","Y"}
oUF.Tags['BRFPom'] = function(u) 
	local c = select(4, UnitAura(u, GetSpellInfo(41635))) if c then return "|cffFFCF7F"..pomCount[c].."|r" end end
oUF.TagEvents['BRFPom'] = "UNIT_AURA"

-- oUF.Tags['BRFPWS'] = function(u) 
	-- local c = select(4, UnitAura(u, GetSpellInfo(17))) if c then return "|cffFFCF7FC|r" end end
-- oUF.TagEvents['BRFPWS'] = "UNIT_AURA"


-- ***************
-- * Update Functions 
-- ***************

-- Updates the given health bar's color based on the color gradient values supplied in settings.
local function updateHealth(health, unit)
	local curhealth, maxhealth = UnitHealth(unit), UnitHealthMax(unit)
	local r, g, b, t
	r, g, b = .25, .25, .25
	local _, class = UnitClass(unit)
	
	if not ns.db.useClassColor then
		r,g,b = ColorGradient(curhealth/maxhealth,ns.db.healthTextureColorEnd,ns.db.healthTextureColorMid,ns.db.healthTextureColor)
	else
		t = oUF.colors.class[class]
		if(t and type(t) == 'table') then
			r, g, b = t[1], t[2], t[3]
		end
	end
	if(b) then
		health:SetStatusBarColor(r, g, b, 1)
	end
end

-- Used by options window to do real time updates
function ns:UpdateHealthOptions(hp)
	hp:SetStatusBarTexture(ns.db.healthTexturePath)

	if not ns.db.powerbar then
		hp:SetHeight(ns.db.height)
		hp:SetWidth(ns.db.width)
	end
	
	hp:ClearAllPoints()
	hp:SetPoint"TOP"
	hp:SetPoint"LEFT"
	hp:SetPoint"RIGHT"
end

-- Updates the given power bar's color based on power type or if they should be showed at all.
local function updatePower(power, unit)
	local _, ptype = UnitPowerType(unit)
	local self = power.__owner
	local _, class = UnitClass(unit)

	if ptype == 'MANA' or not ns.db.onlyMana then
		power:Show()
		power:SetHeight(ns.db.height*ns.db.powerbarsize)
		self.Health:SetHeight((0.98 - ns.db.powerbarsize)*ns.db.height)
	else
		power:Hide()
		self.Health:SetHeight(ns.db.height)
	end

	local r, g, b, t
	
	
	if ns.db.powerclass then
		t = oUF.colors.class[class]
	else
		t = ns.db.powerColor
	end
	
	r, g, b = 1, 1, 1
	if(t and type(t) == 'table') then
		r, g, b = t[1], t[2], t[3]
	end

	if(b) then
		power:SetStatusBarColor(r, g, b, .8)
	end
end

-- Used by options window to do real time updates
function ns:UpdatePowerOptions(power)
	if ns.db.powerbar then
		power:Show()
		power.PostUpdate = updatePower
	else
		power:Hide()
		power.PostUpdate = nil
		return
	end
	power:SetStatusBarTexture(ns.db.powerTexturePath)
	power:ClearAllPoints()
	power:SetPoint"LEFT"
	power:SetPoint"RIGHT"
	power:SetPoint"BOTTOM"
end


-- Shows / Hides the focus border on a unit
local FocusTarget = function(self)
	if UnitIsUnit('focus', self.unit) then
		self.FocusHighlight:SetBackdropColor(.6, .8, 0, 1)
		self.FocusHighlight:Show()
		--self.Border:Hide()
	else
		self.FocusHighlight:Hide()
		--self.Border:Show()
	end
end


-- Updates the various buff bars on the unitframe with the new values, this is called very often.
local function UpdateBars(self)
	local bars = self.bars
	local timenow = GetTime()
	
	for index = 1, #bars do
		local bar = bars[index]
		if not bar:IsVisible() then
			break
		end
		if bar.aura.expirationTime and bar.aura.expirationTime >= timenow then 
			local timeleft = bar.aura.expirationTime - timenow
			--print("updating bar :: ".. timeleft)
			if not timeleft or timeleft <= 0 then
				timeleft = 0.000001
			end
			bar:SetValue(timeleft)
		end
	end
	bars=nil
end


-- Updates the various buff bars when buff state changes
local cur = {0,0,0}
local AuraUpdateHelper = function(self,auraType)
	local bars = self.bars
	local index = 1
	--local cur={0,0,0}
	cur[1]=0
	cur[2]=0
	cur[3]=0
	local highlightCur=0
	local dispelCur=0
	local bcolorCur=0
	local HideBar = false
	local passPersonalCheck = false
	
	-- Loop until there are no more auras
	while true do
		local name, rank, texture, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellID = UnitAura(self.unit, index, auraType)
		if not name then break end
		-- This is sort of a quick fix to not having to copy / paste the below information many times or breaking it out into yet another function. Its mess but works.
		local barIndex = -1
		passPersonalCheck = false
		HideBar = false
		if (ns.auraLists[1][name]) then
			barIndex = 1
			passPersonalCheck = true
			if not ns.db.displayNonClassBuffs and ns.auraLists[barIndex][name][6] ~= "ALL" and ns.auraLists[barIndex][name][6] ~= class then HideBar = true end
		elseif (ns.auraLists[2][name]) then
			barIndex = 2
			passPersonalCheck = true
			if not ns.db.displayNonClassBuffs and not ns.db.UseTopBarForBossDebuffs and ns.auraLists[barIndex][name][6] ~= "ALL" and ns.auraLists[barIndex][name][6] ~= class then HideBar = true end
		elseif (ns.auraLists[3][name]) then
			barIndex = 3
			-- Bar 3 should only show things from you and noone else.
			if unitCaster == "player" then passPersonalCheck = true end
			if not ns.auraLists[barIndex][name][8] then HideBar = true end
			if not ns.db.displayNonClassBuffs and ns.auraLists[barIndex][name][9] ~= class then HideBar = true end
		else
		end
		
		-- Handle the bars
		if barIndex>0 and passPersonalCheck and ns.auraBarTypes[barIndex] == auraType then
			local curBar=bars[barIndex]
			-- If the current buff is listed by the user to be monitored and has the highest priority, we do this thing.
			if ns.auraLists[barIndex][name][5] > cur[barIndex] and not HideBar then
				cur[barIndex] = ns.auraLists[barIndex][name][5]
				curBar.aura.name = name
				curBar.aura.count = count
				curBar.aura.debuffType = debuffType
				curBar.aura.duration = duration
				curBar.aura.expirationTime = expirationTime
				curBar.aura.unitCaster = unitCaster
				curBar.aura.noTime = (duration == 0 and expirationTime == 0)
				
				--very dirty hack to get around rewriting
				if (ns.db.UseTopBarForBossDebuffs and barIndex == 2) then
					curBar:SetStatusBarColor(ns.auraLists[barIndex][name][1] + ns.auraLists[barIndex][name][1] * ns.db.bossDebuffBarColorAmplification, 
											ns.auraLists[barIndex][name][2] + ns.auraLists[barIndex][name][2] * ns.db.bossDebuffBarColorAmplification, 
											ns.auraLists[barIndex][name][3] + ns.auraLists[barIndex][name][3] * ns.db.bossDebuffBarColorAmplification,
											ns.db.bossDebuffBarAlpha)
				else
					curBar:SetStatusBarColor(ns.auraLists[barIndex][name][1],ns.auraLists[barIndex][name][2],ns.auraLists[barIndex][name][3],ns.auraLists[barIndex][name][4])
				end
				
				if curBar.aura.noTime then
					curBar:SetMinMaxValues(0, 1)
					curBar:SetValue(1)
				else
					curBar:SetMinMaxValues(0, duration)
					curBar:SetValue(expirationTime - GetTime())
				end
			end
		end
		
		--Handle the bossHighlight (lazy hax)
		if ns.bossHighlights[name] then
			local bossHighlightAura = ns.bossHighlights[name]
			if bossHighlightAura[5] > highlightCur then
				highlightCur = bossHighlightAura[5]
				self.bossHighlight.texture:SetTexture(bossHighlightAura[1],bossHighlightAura[2],bossHighlightAura[3],bossHighlightAura[4])
				self.bossHighlight:Show()
			end
		
		end
		
		--Handel the Dispel border
		if dispellist[debuffType] and auraType == "HARMFUL" then
			if dispellPriority[debuffType] and dispellPriority[debuffType] > dispelCur then
				dispelCur = dispellPriority[debuffType]
				self.dispelBorder:SetBackdropColor(ns.db.dispelColors[debuffType][1], ns.db.dispelColors[debuffType][2], ns.db.dispelColors[debuffType][3], ns.db.dispelColors[debuffType][4])
				self.dispelBorder:Show()
			end
		end
		
		--Handle the base border color
		
		if ns.auras.baseBorderColor[name] and ns.auraBarTypes[4] == auraType and ((not ns.db.displayNonClassBuffs and (ns.auras.baseBorderColor[name][6] == class or ns.auras.baseBorderColor[name][6] == "ALL")) or ns.db.displayNonClassBuffs) and ns.auras.baseBorderColor[name][5] > bcolorCur then
			bcolorCur = ns.auras.baseBorderColor[name][5]
			self.Border:SetBackdropColor(ns.auras.baseBorderColor[name][1],ns.auras.baseBorderColor[name][2],ns.auras.baseBorderColor[name][3])
			if ns.db.borderGlow then
				self.Border:SetBackdropBorderColor(ns.auras.baseBorderColor[name][1],ns.auras.baseBorderColor[name][2],ns.auras.baseBorderColor[name][3])
			end
		end
		
		index = index + 1
	end
	-- If we dont have a highlight, hide the texture.
	if highlightCur == 0 then
		self.bossHighlight:Hide()
	end
	
	-- If we dont have a dispellable debuff hide the border
	if dispelCur == 0 and auraType == "HARMFUL" then
		self.dispelBorder:Hide()
	end
	
	if bcolorCur == 0 and ns.auraBarTypes[4] == auraType then
		if ns.db.borderGlow then
			self.Border:SetBackdropColor(ns.db.borderColor[1],ns.db.borderColor[2],ns.db.borderColor[3],0)
			self.Border:SetBackdropBorderColor(ns.db.glowColor[1],ns.db.glowColor[2],ns.db.glowColor[3])
		else
			self.Border:SetBackdropColor(ns.db.borderColor[1],ns.db.borderColor[2],ns.db.borderColor[3])
		end
	end
	
	-- if we dont have a bar to display on our buff bars, lets hide them
	
	for index = 1, #bars do
		if cur[index] == 0 and ns.auraBarTypes[index] == auraType then
			bars[index]:SetMinMaxValues(0, 1)
			bars[index]:SetValue(0)
			bars[index].aura.expirationTime=nil
		end
	end
end


-- Updates the various buff bars when buff state changes using the function above for both harmful and helpful spells
local AuraUpdate = function(self)
	AuraUpdateHelper(self,"HELPFUL")
	AuraUpdateHelper(self,"HARMFUL")
end

-- ***************
-- * oUF Styles / Initalization
-- ***************

-- The main style , a recreation of my main rdx frames
local orginalStyle = function(self)
	self.menu = menu
	
	if ns.db.showToolTip then
		self:SetScript('OnEnter', UnitFrame_OnEnter)
		self:SetScript('OnLeave', UnitFrame_OnLeave)
	end
	
	if ns.db.borderGlow then
		border = {
			edgeFile = [=[Interface\AddOns\oUF_BrethrenRF\media\glowTex.tga]=], edgeSize = 5,
			bgFile = [=[Interface\ChatFrame\ChatFrameBackground]=],
			insets = {left = 3, right = 3, top = 3, bottom = 3}
		}
	else
		border = {
			bgFile = [=[Interface\AddOns\oUF_BrethrenRF\media\white.tga]=],
			insets = {top = -1, left = -1, bottom = -1, right = -1},
		}
	end
	
	self.bars = {}
	self:SetFrameLevel(5)
	-- Backdrop
	self.BG = CreateFrame("Frame", nil, self)
	self.BG:SetPoint("TOPLEFT", self, "TOPLEFT")
	self.BG:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT")
	self.BG:SetFrameLevel(5)
	self.BG:SetBackdrop(backdrop)
	self.BG:SetBackdropColor(ns.db.BackgroundColor[1], ns.db.BackgroundColor[2], ns.db.BackgroundColor[3])

	--Register for clicks, never use anyup.
	self:RegisterForClicks"AnyDown"
	self:SetAttribute("*type2", "menu")

	-- Health bar
	local hp = CreateFrame"StatusBar"
	hp:SetStatusBarTexture(ns.db.healthTexturePath)
	fixStatusbar(hp)
	hp:SetOrientation("HORIZONTAL")
	hp:SetParent(self)
	hp:SetPoint"TOP"
	hp:SetPoint"LEFT"
	hp:SetPoint"RIGHT"
	hp.frequentUpdates = true
	hp.Smooth = true
	hp.PostUpdate = updateHealth
	self.Health = hp
	
	-- Health prediction bars
	if ns.db.healPrediction then
		-- mine
		local hpmpColors = ns.db.predictedHealthColorYours
		hpmp = CreateFrame"StatusBar"
		hpmp:SetStatusBarTexture(ns.db.healthTexturePath, 'BORDER')
		hpmp:SetStatusBarColor(hpmpColors[1],hpmpColors[2],hpmpColors[3],hpmpColors[4])
		fixStatusbar(hpmp)
		hpmp:SetOrientation("HORIZONTAL")
		hpmp:SetParent(self)
		hpmp:SetPoint('TOPLEFT', hp:GetStatusBarTexture(), 'TOPRIGHT')
		hpmp:SetPoint('BOTTOMLEFT', hp:GetStatusBarTexture(), 'BOTTOMRIGHT')
		hpmp:SetWidth(self:GetWidth())
		hpmp.Smooth=true
		
		-- theirs
		local hptpColors = ns.db.predictedHealthColorTheirs
		hptp = CreateFrame"StatusBar"
		hptp:SetStatusBarTexture(ns.db.healthTexturePath, 'BORDER')
		hptp:SetStatusBarColor(hptpColors[1],hptpColors[2],hptpColors[3],hptpColors[4])
		fixStatusbar(hptp)
		hptp:SetOrientation("HORIZONTAL")
		hptp:SetParent(self)
		hptp:SetPoint('TOPLEFT', hpmp:GetStatusBarTexture(), 'TOPRIGHT')
		hptp:SetPoint('BOTTOMLEFT', hpmp:GetStatusBarTexture(), 'BOTTOMRIGHT')
		hptp:SetWidth(self:GetWidth())
		hptp.Smooth=true
	
		self.HealPrediction = {}
		self.HealPrediction.myBar = hpmp
		self.HealPrediction.otherBar = hptp
		self.HealPrediction.maxOverflow = ns.db.healPredictionOverflow and 1.2 or 1

	end
	
	-- Group number or buff stack / occurance text
	local group = self.Health:CreateFontString(nil, "OVERLAY")
	group:SetPoint("LEFT",self,"LEFT",2,0)
	group:SetJustifyH("LEFT")
	group:SetJustifyV("CENTER")
	group:SetFont(ns.db.fontPath, ns.db.fontsize-2, ns.db.outline)
	group:SetShadowOffset(0, 0)
	--if ns.db.fontShadow then group:SetShadowOffset(1, -1) end
	group.overrideUnit = true
	self:Tag(group, "[BRFGroupHotCount]")
	self.groupText = group
	
	-- Unit name text
	local name = self.Health:CreateFontString(nil, "OVERLAY")
	name:SetPoint("LEFT",group,"RIGHT",2,0)
	if ns.db.outline then
		if ns.db.fontShadow then
			name:SetPoint("LEFT",group,"RIGHT",-1,0)
		else
			name:SetPoint("LEFT",group,"RIGHT",0,0)
		end
	else
		name:SetPoint("LEFT",group,"RIGHT",3,0)
	end
	name:SetJustifyH("LEFT")
	name:SetJustifyV("CENTER")
	name:SetFont(ns.db.fontPath, ns.db.fontsize, ns.db.outline)
	name:SetShadowOffset(0, 0)
	if ns.db.fontShadow then name:SetShadowOffset(1, -1) end
	name.overrideUnit = true
	self:Tag(name, "[BRFname]")
	self.nameText = name
	
	-- Unit health text
	local health = self.Health:CreateFontString(nil, "OVERLAY")
	health:SetPoint("RIGHT")
	health:SetJustifyH("RIGHT")
	health:SetJustifyV("CENTER")
	health:SetFont(ns.db.fontPath, ns.db.fontsize-2, ns.db.outline)
	health:SetShadowOffset(0, 0)
	if ns.db.fontShadow then health:SetShadowOffset(1, -1) end
	health.overrideUnit = true
	self:Tag(health, "[BRFhealth] ")
	self.healthText = health
	
	-- POM symbol
	local symbols = "Interface\\AddOns\\oUF_BrethrenRF\\media\\PIZZADUDEBULLETS.ttf"
	local AuraStatusTR = self.Health:CreateFontString(nil, "OVERLAY")
	AuraStatusTR:ClearAllPoints()
	AuraStatusTR:SetPoint("TOPRIGHT", 6, 4)
	AuraStatusTR:SetFont(symbols, ns.db.symbolsize, "THINOUTLINE")
	self:Tag(AuraStatusTR, "[BRFPom]")
	
	-- local AuraStatusBR = self.Health:CreateFontString(nil, "OVERLAY")
	-- AuraStatusBR:ClearAllPoints()
	-- AuraStatusBR:SetPoint("BOTTOMRIGHT", 6, -4)
	-- AuraStatusBR:SetFont(symbols, ns.db.symbolsize, "THINOUTLINE")
	-- self:Tag(AuraStatusBR, "[BRFPWS]")
	
	
	
	-- Power bar
	local pp = CreateFrame"StatusBar"
	pp:SetStatusBarTexture(ns.db.powerTexturePath)
	fixStatusbar(pp)
	pp:SetOrientation("HORIZONTAL")
	pp:SetParent(self)
	pp.PostUpdate = updatePower
	pp.frequentUpdates = true
	self.Power = pp
	pp.Smooth = true
	ns:UpdatePowerOptions(self.Power)
	

	--Highlight tex
	local hl = hp:CreateTexture(nil, "OVERLAY")
	hl:SetAllPoints(self)
	hl:SetTexture([=[Interface\AddOns\oUF_BrethrenRF\media\white.tga]=])
	hl:SetVertexColor(1,1,1,.1)
	hl:SetBlendMode("ADD")
	hl:Hide()
	self.Highlight = hl


	-- always on border
	local Border = CreateFrame("Frame", nil, self)
	if ns.db.borderGlow then
		Border:SetPoint("TOPLEFT", self, "TOPLEFT",-4, 4)
		Border:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 4, -4)
	else
		Border:SetPoint("TOPLEFT", self, "TOPLEFT")
		Border:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT")
	end
	Border:SetBackdrop(border)
	
	if ns.db.borderGlow then 
		Border:SetBackdropColor(ns.db.borderColor[1],ns.db.borderColor[2],ns.db.borderColor[3],0)
		Border:SetBackdropBorderColor(ns.db.glowColor[1],ns.db.glowColor[2],ns.db.glowColor[3])
	else
		Border:SetBackdropColor(ns.db.borderColor[1],ns.db.borderColor[2],ns.db.borderColor[3])
	end
	Border:SetFrameLevel(2)
	Border:Show()
	self.Border = Border

	-- Border Frame level 1
	local BorderFrame1 = CreateFrame("Frame", nil, self)
	BorderFrame1:SetPoint("TOPLEFT", hp, "TOPLEFT")
	BorderFrame1:SetPoint("BOTTOMRIGHT", hp, "BOTTOMRIGHT")
	BorderFrame1:Show()
	BorderFrame1:SetFrameLevel(3)
	
	-- Border Frame level 2
	local BorderFrame2 = CreateFrame("Frame", nil, self)
	BorderFrame2:SetPoint("TOPLEFT", hp, "TOPLEFT")
	BorderFrame2:SetPoint("BOTTOMRIGHT", hp, "BOTTOMRIGHT")
	BorderFrame2:Show()
	BorderFrame2:SetFrameLevel(4)
	
	-- Border debuff Bar
	local BorderBar = CreateFrame("StatusBar", nil, BorderFrame1)
	BorderBar:SetStatusBarTexture("Interface\\AddOns\\oUF_BrethrenRF\\media\\white")
	fixStatusbar(BorderBar)
	BorderBar:SetOrientation("HORIZONTAL")
	BorderBar:SetPoint("TOPLEFT", self, "TOPLEFT",-1,1)
	BorderBar:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT",1,-1)
	--BorderBar:SetFrameLevel(3)
	BorderBar:SetMinMaxValues(0, 1)
	BorderBar:SetValue(0)
	self.bars[1]=BorderBar
	BorderBar.aura = {}
	BorderBar.types = {["HELPFUL"]=true, ["HARMFUL"]=true}
	
	
	-- Aura frame
	local AuraFrame = CreateFrame("Frame", nil, self)
	AuraFrame:SetPoint("TOPLEFT", hp, "TOPLEFT")
	AuraFrame:SetPoint("BOTTOMRIGHT", hp, "BOTTOMRIGHT")
	AuraFrame:Show()
	AuraFrame:SetFrameLevel(7)
	
	-- Top Debuff Bar
	local topBar = CreateFrame("StatusBar", nil, AuraFrame)
	topBar:SetStatusBarTexture("Interface\\AddOns\\oUF_BrethrenRF\\media\\white")
	fixStatusbar(topBar)
	topBar:SetOrientation("HORIZONTAL")
	topBar:SetHeight(ns.db.height*ns.db.timerBarSize)
	topBar:SetWidth(ns.db.width)
	topBar:SetPoint("TOP")	
	topBar:SetMinMaxValues(0, 1)
	topBar:SetValue(0)
	self.bars[2]=topBar
	topBar.aura = {}
	topBar.types = {["HELPFUL"]=true, ["HARMFUL"]=true}
	topBar:Show()
	
	-- Bottom Debuff Bar
	local bottombat = CreateFrame("StatusBar", nil, AuraFrame)
	bottombat:SetStatusBarTexture("Interface\\AddOns\\oUF_BrethrenRF\\media\\white")
	fixStatusbar(bottombat)
	bottombat:SetOrientation("HORIZONTAL")
	bottombat:SetHeight(ns.db.height*ns.db.timerBarSize)
	bottombat:SetWidth(ns.db.width)
	bottombat:SetPoint("BOTTOM")	
	bottombat:SetMinMaxValues(0, 1)
	bottombat:SetValue(0)
	self.bars[3]=bottombat
	bottombat.aura = {}
	bottombat.types = {["HELPFUL"]=true, ["HARMFUL"]=false}
	bottombat:Show()
	
	-- Boss Highlights
	local bossHighlightFrame = CreateFrame("Frame", nil, self)
	bossHighlightFrame:SetPoint("TOPLEFT", self, "TOPLEFT")
	bossHighlightFrame:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT")
	bossHighlightFrame:Show()
	bossHighlightFrame:SetFrameLevel(7)
	bossHighlightFrame.texture = bossHighlightFrame:CreateTexture()
	bossHighlightFrame.texture:SetAllPoints(bossHighlightFrame)
	self.bossHighlight = bossHighlightFrame
	
   
	-- Focus Border
	local fBorder = CreateFrame("Frame", nil, BorderFrame1)
	fBorder:SetPoint("TOPLEFT", self, "TOPLEFT")
	fBorder:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT")
	fBorder:SetBackdrop(thinBorder)
	fBorder:Hide()
	self.FocusHighlight = fBorder
	
	-- Dispel Border
	local dispelBorder = CreateFrame("Frame", nil, BorderFrame1)
	dispelBorder:SetPoint("TOPLEFT", self, "TOPLEFT")
	dispelBorder:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT")
	dispelBorder:SetBackdrop(thinBorder)
	dispelBorder:Hide()
	self.dispelBorder = dispelBorder
	

	-- There might be too many of these damn icons lol
	-- Raid Icons
	local ricon = hp:CreateTexture(nil, 'OVERLAY')
	ricon:SetPoint("TOP", self, 0, 5)
	ricon:SetSize(ns.db.iconsize, ns.db.iconsize)
	self.RaidIcon = ricon
	
	-- Leader Icon
	self.Leader = hp:CreateTexture(nil, "OVERLAY")
	self.Leader:SetPoint("TOPLEFT", self, 0, 8)
	self.Leader:SetSize(ns.db.iconsize, ns.db.iconsize)
	self.Leader:SetAlpha(0)
	if ns.db.leadIcon then self.Leader:SetAlpha(1) end

	-- Assistant Icon
	self.Assistant = hp:CreateTexture(nil, "OVERLAY")
	self.Assistant:SetPoint("TOPLEFT", self, 0, 8)
	self.Assistant:SetSize(ns.db.iconsize, ns.db.iconsize)
	self.Assistant:SetAlpha(0)
	if ns.db.leadIcon then self.Assistant:SetAlpha(1) end

	-- Master looter Icon
	local masterlooter = hp:CreateTexture(nil, 'OVERLAY')
	masterlooter:SetSize(ns.db.iconsize, ns.db.iconsize)
	masterlooter:SetPoint('LEFT', self.Leader, 'RIGHT')
	masterlooter:SetAlpha(0)
	self.MasterLooter = masterlooter
	if ns.db.leadIcon then self.MasterLooter:SetAlpha(1) end
	
	-- LFD Icon
	self.LFDRole = hp:CreateTexture(nil, 'OVERLAY')
	self.LFDRole:SetSize(ns.db.iconsize, ns.db.iconsize)
	self.LFDRole:SetPoint('RIGHT', self, 'LEFT', ns.db.iconsize/2, ns.db.iconsize/2)
	self.LFDRole:SetAlpha(0)
	if ns.db.lfdIcon then self.LFDRole:SetAlpha(1) end

	-- ReadyCheck Icon
   self.ReadyCheck = hp:CreateTexture(nil, "OVERLAY")
   self.ReadyCheck:SetPoint("TOP", self)
   self.ReadyCheck:SetSize(ns.db.iconsize, ns.db.iconsize)

	-- Range
	self.Range = {
		insideAlpha = ns.db.inRange,
		outsideAlpha = ns.db.outsideRange,
	}


	-- Add events
	self:RegisterEvent('PLAYER_FOCUS_CHANGED', FocusTarget)
	self:RegisterEvent('RAID_ROSTER_UPDATE', FocusTarget)
	self:RegisterEvent('RAID_ROSTER_UPDATE', updateOccurenceStoreEvent)
	self:RegisterEvent('PARTY_MEMBERS_CHANGED', updateOccurenceStoreEvent)
	self:RegisterEvent('PLAYER_LOGIN', updateOccurenceStoreEvent)
	self:RegisterEvent('PLAYER_ENTERING_WORLD', getzone)
	self:RegisterEvent('UNIT_AURA', AuraUpdate)
	self:SetScript('OnUpdate', UpdateBars)
	
	--self:SetScale(ns.db.scale)
	
	table.insert(ns._Objects, self)
end

oUF:RegisterStyle("BrethrenRF", orginalStyle)

local pos, posRel, colX, colY
local function BRFHeader(name, group, temp, pet)
	local point, growth, xoff, yoff
	if ns.db.HorizontalGroupGrowth then
		point = "LEFT"
		xoff = ns.db.spacing
		yoff = 0
		if ns.db.growthDirection == "UP" then
			growth = "BOTTOM"
			pos = "BOTTOMLEFT"
			posRel = "TOPLEFT"
			colY = ns.db.spacing
			--if ns.db.splitGroups then colY = colY + (ns.db.height * ns.db.scale - ns.db.height) end
		else
			growth = "TOP"
			pos = "TOPLEFT"
			posRel = "BOTTOMLEFT"
			colY = -ns.db.spacing
			--if ns.db.splitGroups then colY = colY - (ns.db.height * ns.db.scale - ns.db.height) end
		end
	else
		point = "TOP"
		xoff = 0
		yoff = -ns.db.spacing
		if ns.db.growthDirection == "RIGHT" then
			growth = "LEFT"
			pos = "TOPLEFT"
			posRel = "TOPRIGHT"
			colX = ns.db.spacing
			--if ns.db.splitGroups then colX = colX + (ns.db.width * ns.db.scale - ns.db.width) end
		elseif ns.db.growthDirection == "UP" then
			growth = "BOTTOM"
			pos = "BOTTOMLEFT"
			posRel = "TOPLEFT"
			colY = ns.db.spacing
			if ns.db.splitGroups then colY = colY + 6 end
		elseif ns.db.growthDirection == "DOWN" then
			growth = "BOTTOM"
			pos = "TOPLEFT"
			posRel = "BOTTOMLEFT"
			colY = -ns.db.spacing
			if ns.db.splitGroups then colY = colY - ns.db.height end
		else
			growth = "RIGHT"
			pos = "TOPRIGHT"
			posRel = "TOPLEFT"
			colX = -ns.db.spacing
			--if ns.db.splitGroups then colX = colX - (ns.db.width * ns.db.scale - ns.db.width) end
		end
	end

	local numUnits = ns.db.splitGroups and 5 or ns.db.numUnits

	local initconfig = [[
	self:SetWidth(%d)
	self:SetHeight(%d)
	]]

	if pet then 
		initconfig = [[ 
		self:SetWidth(%d)		
		self:SetHeight(%d)		   
		self:SetAttribute('unitsuffix', 'pet')				 
		]]
	end

	local template = temp or nil
	local header = oUF:SpawnHeader(name, template, 'raid,party,solo',
	'oUF-initialConfigFunction', (initconfig):format(ns.db.width, ns.db.height),
	'showPlayer', ns.db.player,
	'showSolo', ns.db.solo,
	'showParty', ns.db.party,
	'showRaid', ns.db.raid,
	'xOffset', xoff,
	'yOffset', yoff,
	'point', point,
	'groupFilter', group,
	'groupingOrder', '1,2,3,4,5,6,7,8',
	'groupBy', 'GROUP',
	'sortMethod', ns.db.sortMethod,
	'maxColumns', ns.db.numCol,
	'unitsPerColumn', numUnits,
	'columnSpacing', ns.db.spacing,
	'columnAnchorPoint', growth)

	return header
end

ns._Headers = {}
ns._Objects = {}
oUF:Factory(function(self)
	ns.Enable()
	self:SetActiveStyle"BrethrenRF"
	if ns.db.splitGroups then
		local raid = {}
		for i=1, ns.db.numCol do
			local group = BRFHeader("Raid_BrethrenRF"..i, i)
			if i == 1 then
				group:SetPoint(pos, "oUF_BrethrenRFRaidFrame", pos)
			else
				group:SetPoint(pos, raid[i-1], posRel, colX or 0, colY or 0)
			end
			raid[i] = group
			ns._Headers[group:GetName()] = group
			group:SetScale(ns.db.scale)
		end
	else
		local raid = BRFHeader("Raid_BrethrenRF")
		raid:SetPoint("TOPLEFT", "oUF_BrethrenRFRaidFrame", "TOPLEFT")
		ns._Headers[raid:GetName()] = raid
		raid:SetScale(ns.db.scale)
	end

	if ns.db.pets then
		local pet = BRFHeader("Pet_BrethrenRF", nil, 'SecureGroupPetHeaderTemplate', true)
		pet:SetPoint(pos, "oUF_BrethrenRFPetFrame", pos)
		pet:SetAttribute('useOwnerUnit', true)
		ns._Headers[pet:GetName()] = pet
		pet:SetScale(ns.db.scale)
	end

	if ns.db.MT then
		local tank = BRFHeader("MT_BrethrenRF")
		tank:SetPoint(pos, "oUF_BrethrenRFMTFrame", pos)
		ns._Headers[tank:GetName()] = tank
		
		if oRA3 then
			tank:SetAttribute("initial-unitWatch", true)
			tank:SetAttribute("nameList", table.concat(oRA3:GetSortedTanks(), ","))

			local tankhandler = {}
			function tankhandler:OnTanksUpdated(event, tanks) 
				tank:SetAttribute("nameList", table.concat(tanks, ","))
			end
			oRA3.RegisterCallback(tankhandler, "OnTanksUpdated")
		else
			tank:SetAttribute('groupFilter', 'MAINTANK')
		end
		tank:SetScale(ns.db.scale)
	end
end)



-- addon load, I guess I dont really need this anymore.
local f = CreateFrame("Frame")
f:RegisterEvent("ADDON_LOADED")
f:SetScript("OnEvent", function(self, event, addon)
	if addon ~= ADDON_NAME then return end
	
	ns:InitDB()

	--set topbar to bossdebuffs if option is set	
	if ns.db.UseTopBarForBossDebuffs then
		ns.auraLists[2]=ns.bossHighlights
	end
	
	local f = CreateFrame('Frame', nil, InterfaceOptionsFrame)
	f:SetScript('OnShow', function(self)
		self:SetScript('OnShow', nil)
		if not IsAddOnLoaded('oUF_BrethrenRF_Config') then
			LoadAddOn('oUF_BrethrenRF_Config')
		end
	end)
	
	-- Blizzard unhiding their frames when the interface window closes, wtf.
	f:SetScript('OnHide', function(self)
		CompactRaidFrameManager:UnregisterAllEvents()
		CompactRaidFrameManager:Hide()
		CompactRaidFrameContainer:UnregisterAllEvents()
		CompactRaidFrameContainer:Hide() 
	end)
	
	self:UnregisterEvent("ADDON_LOADED")
end)

-- PlayerPowerBarAlt event, it gets reanchored when it it is hidden/show it looks like
local fPA = CreateFrame("Frame")
fPA:RegisterEvent("UNIT_POWER_BAR_SHOW")
fPA:RegisterEvent("UNIT_POWER")
fPA:SetScript("OnEvent", function()
	PlayerPowerBarAlt:ClearAllPoints()
	PlayerPowerBarAlt:SetPoint("TOP","oUF_BrethrenRFBossPower","TOP")	
end)


SLASH_OUF_BRETHRENRF1 = '/brf'
SlashCmdList['OUF_BRETHRENRF'] = function(inp)
	if(inp:match("%C+") or inp:match("%S+") or inp:match("%O+")) then
		if not IsAddOnLoaded('oUF_BrethrenRF_Config') then
			LoadAddOn('oUF_BrethrenRF_Config')
		end
		InterfaceOptionsFrame_OpenToCategory(ADDON_NAME)
	else
		ns.Movable()
	end
end

BRF_NS = ns -- Have to use this so config can get to internal stuff.